import {defineComponent, Transition, inject, onMounted, onBeforeUnmount, provide, computed, ref, PropType} from "vue";
import {FormContext, FormItemContext, FormItemKey, FormKey} from "./types";
import Schema, {RuleItem} from 'async-validator';

let id = 0;
function generateId () {
  return `item_${id++}`;
}

export default defineComponent({
  name: 'FormItem',
  props: {
    label: {
      type: String,
      default: ''
    },
    prop: {
      type: String,
      default: ''
    },
    errMsg: {
      type: String,
      default: ''
    },
    rules: [Object, Array] as PropType<RuleItem | RuleItem[]>
  },
  setup(props, { slots }) {
    const id = generateId();
    const parent = inject<FormContext>(FormKey)!;
    let errMsg = ref(props.errMsg);

    const getRules = () => {
      if (props.rules) {
        return props.rules;
      }
      if (parent.rules) {
        return parent.rules[props.prop];
      }
      return null;
    }

    const validTrigger = computed(() => getRules()?.trigger || 'change');

    const validate = (val?: string): Promise<any> => {
      const rules = getRules();
      if (rules && props.prop) {
        const value = val ?? parent.model[props.prop];
        const schema = new Schema({ [props.prop]: rules });
        return schema.validate({ [props.prop]: value }).then(() => {
          errMsg.value = '';
          return true;
        }).catch(({ errors }) => {
          errMsg.value = errors[0].message;
          return Promise.reject(errors);
        });
      }
      return Promise.resolve(true);
    }

    const handlerValueChange = (value: any) => {
      if (validTrigger.value === 'change') {
        validate(value);
      }
    }
    const handlerControlBlur = (value: any) => {
      if (validTrigger.value === 'blur') {
        validate(value);
      }
    }


    const FormItemInstance: FormItemContext = {
      id,
      validate,
      handlerControlBlur,
      handlerValueChange
    }
    provide(FormItemKey, FormItemInstance);
    onMounted(() => {
      parent.addItem({
        id,
        prop: props.prop,
        validate
      });
    });
    onBeforeUnmount(() => {
      parent.removeItem(id);
    });
    const renderLabel = () => {
      return slots.label ? slots.label() : <label class="item-label">{ props.label }</label>;
    }
    return () => {
      return (
        <div class="ant-form-item">
          { renderLabel() }
          <div class="item-content">
            <div class="item-control-wrap">
              { slots.default!() }
            </div>
            <Transition name="fade">
              <p class="item-error" v-show={ errMsg.value }>{ errMsg.value }</p>
            </Transition>
          </div>
        </div>
      );
    }
  }
});
